package ilender.controller;

import lombok.*;

import com.google.gson.*;
import org.joda.time.*;

import ilender.annotations.*;
import ilender.dispatching.ControllerTools;
import ilender.mappers.*;
import ilender.models.*;
import ilender.util.*;
import ilender.formatting.*;
import ilender.facebook.*;

/**
 * @see Controller
 */
@Controller("offers")
public class OffersController{
	/**
	 * Handles registering an offer.
	 *
	 * @param req The request.
	 * @param item The item.
	 * @param tools The ControllerTools used for the request.
	 */
	public static JsonElement registerOffer(MRequest req,MItem item,ControllerTools tools){
		MOffer offer=new MOffer();
		offer.setRequest(req);
		offer.setItem(item);
		offer.setOffered_at(DateTime.now());
		offer.setOffered_by_id(tools.fbUser.id);

		if(null==req.getUntil_date()){
			offer.setReturn_due_date(DateMidnight.now().plusDays(14));
		}else{
			offer.setReturn_due_date(req.getUntil_date());
		}

		if(item.getFacebook_user_id()==tools.fbUser.id){
			tools.fbUser.graphAPI.getFBUser(req.getFacebook_user_id())
			.notification().setReference(offer).setTemplate(String.format(
					"@[%s] has the %s you want to borrow, and offers to lend it to you until %s via Rebay.",
					tools.fbUser.id,item.getName(),
					DateTimeFormatting.forJsonDateMidnight().print(offer.getReturn_due_date())
					)).post();
			offer.setItem_owner_agreed(true);
		}
		if(req.getFacebook_user_id()==tools.fbUser.id){
			offer.setRequester_agreed(true);
			tools.fbUser.graphAPI.getFBUser(item.getFacebook_user_id())
			.notification().setReference(offer).setTemplate(String.format(
					"@[%s] wants to borrow your %s until %s via Rebay.",
					tools.fbUser.id,item.getName(),
					DateTimeFormatting.forJsonDateMidnight().print(offer.getReturn_due_date())
					)).post();
		}

		if(null==offer.trySave(tools.session.getMapper(OffersMapper.class))){
			return JsonTools.makeObject("offer",offer);
		}else{
			return new JsonPrimitive("Offer already exists");
		}
	}

	/**
	 * Accept an offer.
	 *
	 * @param request <pre>
	 * {
	 *     form_data:{
	 *         offer_id:(the id of the offer to accept),
	 *     }
	 * }
	 * </pre>
	 * @return <pre>
	 * {
	 *    offer:(offer cardlet)
	 * }
	 * </pre>
	 */
	public static JsonElement accept(JsonObject request,ControllerTools tools){
		JsonObject formData=request.getAsJsonObject("form_data");
		OffersMapper offersMapper=tools.session.getMapper(OffersMapper.class);
		MOffer offer=offersMapper.find(Long.valueOf(formData.get("offer_id").getAsString()));
		if(tools.fbUser.id==offer.getRequest().getFacebook_user_id()){
			offer.setRequester_agreed(true);
		}else if(tools.fbUser.id==offer.getItem().getFacebook_user_id()){
			offer.setItem_owner_agreed(true);
		}
		String saveResult=offer.trySave(tools.session.getMapper(OffersMapper.class));
		if(null==saveResult){
			return JsonTools.makeObject("offer",offer);
		}else{
			return new JsonPrimitive("Unable to accept offer");
		}
	}
	/**
	 * Reject an offer
	 * @param request
	 * @param tools
	 * @return
	 */
	public static JsonElement reject(JsonObject request,ControllerTools tools){
		JsonObject formData=request.getAsJsonObject("form_data");
		OffersMapper offersMapper=tools.session.getMapper(OffersMapper.class);
		MOffer offer=offersMapper.find(Long.valueOf(formData.get("offer_id").getAsString()));
		offer.setCanceled(true);
		String saveResult=offer.trySave(tools.session.getMapper(OffersMapper.class));
		if(null==saveResult){
			return JsonTools.makeObject("offer",offer);
		}else{
			return new JsonPrimitive("Unable to accept offer");
		}
	}
	/**
	 * Finish an offer(once the item was returned)
	 * @param request <pre>
	 * {
	 *     form_data:{
	 *         offer_id:(the id of the offer to finish),
	 *     }
	 * }
	 * </pre>
	 * @return <pre>
	 * {
	 *    offer:(offer cardlet)
	 * }
	 * </pre>
	 * @return
	 */
	public static JsonElement finish(JsonObject request,ControllerTools tools){
		JsonObject formData=request.getAsJsonObject("form_data");
		OffersMapper offersMapper=tools.session.getMapper(OffersMapper.class);
		MOffer offer=offersMapper.find(Long.valueOf(formData.get("offer_id").getAsString()));

		//Do not allow the borrower to finish the borrow:
		if(tools.fbUser.id!=offer.getItem().getFacebook_user_id()){
			return new JsonPrimitive("Only the lender can finish the borrow!");
		}

		offer.setReturn_actual_time(DateTime.now());

		String saveResult=offer.trySave(tools.session.getMapper(OffersMapper.class));
		if(null==saveResult){
			return JsonTools.makeObject("offer",offer);
		}else{
			return new JsonPrimitive("Unable to accept offer");
		}
	}

	/**
	 * Make an offer for an existing request or item.
	 *
	 * Also creates an item for the request or a request for the item.
	 *
	 * @param request <pre>
	 * {
	 *     form_data:{
	 *         request_id:(the id of the request)
	 *         or item_id:(the id of the item)
	 *     }
	 * }
	 * </pre>
	 * @return <pre>
	 * {
	 *    offer:(offer cardlet)
	 * }
	 * </pre>
	 */
	public static JsonElement makeFor(JsonObject request,ControllerTools tools){
		JsonObject formData=request.getAsJsonObject("form_data");
		RequestsMapper requestsMapper=tools.session.getMapper(RequestsMapper.class);
		ItemsMapper itemsMapper=tools.session.getMapper(ItemsMapper.class);


		if(formData.has("request_id")){
			MRequest req=requestsMapper.find(Long.valueOf(formData.get("request_id").getAsString()));
			MItem item=new MItem();
			item.setFacebook_user_id(tools.fbUser.id);
			item.setCategory(req.getCategory());
			item.setName(req.getTitle());
			item.setDescription(req.getDescription());
			item.setTags(req.getTags());
			item.save(itemsMapper);
			return registerOffer(req, item, tools);
		}else if(formData.has("item_id")){
			MItem item=itemsMapper.find(Long.valueOf(formData.get("item_id").getAsString()));
			MRequest req=new MRequest();
			req.setFacebook_user_id(tools.fbUser.id);
			req.setCategory(item.getCategory());
			req.setTitle(item.getName());
			req.setDescription(item.getDescription());
			req.setTags(item.getTags());
			req.save(requestsMapper);
			return registerOffer(req, item, tools);
		}
		throw new Error();
	}

	/**
	 * Return a list of cardlets of all active and pending offers.
	 *
	 * @param tools The ControllerTools used for the request.
	 * @return A JSON array containing cardlets.
	 */
	public static JsonArray fetchCardlets(ControllerTools tools){
		val offersMapper=tools.session.getMapper(OffersMapper.class);
		JsonArray resultArray=new JsonArray();

		for(MOffer offer:offersMapper.fetchPendingAndActiveForUser(tools.fbUser.id)){
			JsonObject offerElement=tools.gson.toJsonTree(offer).getAsJsonObject();

			// me  - is the lender   .
			if(offer.getItem().getFacebook_user_id()==tools.fbUser.id){
				if(offer.isItem_owner_agreed() && offer.isRequester_agreed()){
					offerElement.addProperty("ejs", "user/table_row/lended_active");
				}
				else if(!(offer.isItem_owner_agreed()) && offer.isRequester_agreed()){
					// wait for your approve  .
					offerElement.addProperty("ejs", "user/table_row/lended_pending");
				}
				else if(offer.isItem_owner_agreed() && !offer.isRequester_agreed()){
					// wait for other side's approval
					offerElement.addProperty("ejs", "user/table_row/lend_offer");
				}
			}
			else { // me  - is the borrower  .
				if(offer.isItem_owner_agreed() && offer.isRequester_agreed()){
					offerElement.addProperty("ejs", "user/table_row/borrowed_active");
				}
				else if(offer.isItem_owner_agreed() && !(offer.isRequester_agreed())){
					// wait for your approve  .
					offerElement.addProperty("ejs", "user/table_row/borrowed_pending");
				}
				else if(!offer.isItem_owner_agreed() && offer.isRequester_agreed()){
					// wait for other side's approval
					offerElement.addProperty("ejs", "user/table_row/borrow_offer");
				}

			}

			if(offerElement.has("ejs")){
				resultArray.add(offerElement);
			}
		}

		return resultArray;
	}
}
